package jmine.tec.script.impl;

import jmine.tec.script.ScriptExecutionContext;
import jmine.tec.script.ScriptExecutor;
import jmine.tec.script.ScriptExecutorException;

/**
 * Define um ciclo padrão de execução de um script. Delega para as implementação as operações que são dependentes do tipo de script sendo
 * executado.
 * 
 * @author jrenaut
 */
public abstract class AbstractScriptExecutor implements ScriptExecutor {

    /**
     * Executa o Script definido no contexto.
     * 
     * @param <R> O tipo do Resultado
     * @param context O contexto de execução
     * @return R
     * @throws ScriptExecutorException Se não for possível executar o script
     */
    public final <R> R execute(final ScriptExecutionContext<R> context) throws ScriptExecutorException {
        if (context == null) {
            throw new NullPointerException("A null context was provided!");
        }

        context.beforeExecution();
        R result;
        try {
            result = this.doExecuteScript(context);
        } finally {
            context.afterExecution();
        }
        return result;
    }

    /**
     * Valida o Script definido no contexto.
     * 
     * @param <R> O tipo do Resultado
     * @param context O contexto de execução
     * @return R
     * @throws ScriptExecutorException Se não for possível executar o script
     */
    public final <R> R getDependencies(final ScriptExecutionContext<R> context) throws ScriptExecutorException {
        if (context == null) {
            throw new NullPointerException("A null context was provided!");
        }

        context.beforeExecution();
        R result;
        try {
            result = this.doGetDependencies(context);
        } finally {
            context.afterExecution();
        }
        return result;
    }

    /**
     * Valida o Script definido no contexto.
     * 
     * @param <R> O tipo do Resultado
     * @param context O contexto de execução
     * @return R
     * @throws ScriptExecutorException Se não for possível executar o script
     */
    public final <R> R getValidations(final ScriptExecutionContext<R> context) throws ScriptExecutorException {
        if (context == null) {
            throw new NullPointerException("A null context was provided!");
        }

        context.beforeExecution();
        R result;
        try {
            result = this.doGetValidations(context);
        } finally {
            context.afterExecution();
        }
        return result;
    }

    /**
     * Sinaliza a implementação que o script deve ser executado.
     * 
     * @param <R> O tipo do resultado
     * @param context contexto
     * @return R
     * @throws ScriptExecutorException Se não for possível executar o script
     */
    protected abstract <R> R doExecuteScript(final ScriptExecutionContext<R> context) throws ScriptExecutorException;

    /**
     * Sinaliza a implementação que o script deve ter suas dependências descritas.
     * 
     * @param <R> O tipo do resultado
     * @param context contexto
     * @return R
     * @throws ScriptExecutorException Se não for possível executar o script
     */
    protected abstract <R> R doGetDependencies(final ScriptExecutionContext<R> context) throws ScriptExecutorException;

    /**
     * Sinaliza a implementação que o script deve validar os dados
     * 
     * @param <R> O tipo do resultado
     * @param context contexto
     * @return R
     * @throws ScriptExecutorException Se não for possível executar o script
     */
    protected abstract <R> R doGetValidations(final ScriptExecutionContext<R> context) throws ScriptExecutorException;
}
